/*
 * Date：10/23/18 10:15 PM
 * Author: guomw
 *
 */

package org.elanfox.intellicommunity.biz.service.core.equipment.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.elanfox.intellicommunity.biz.dto.condition.BaseStationCondition;
import org.elanfox.intellicommunity.biz.dto.equipment.BaseStationSaveDTO;
import org.elanfox.intellicommunity.biz.entity.embeddable.LocatorInfo;
import org.elanfox.intellicommunity.biz.entity.equipment.BaseStationPO;
import org.elanfox.intellicommunity.biz.entity.equipment.BaseStationPO_;
import org.elanfox.intellicommunity.biz.entity.equipment.LocatorPO;
import org.elanfox.intellicommunity.biz.repository.equipment.BaseStationRepository;
import org.elanfox.intellicommunity.biz.service.core.equipment.BaseStationService;
import org.elanfox.intellicommunity.biz.service.core.equipment.LocatorService;
import org.elanfox.intellicommunity.common.constant.ExcelConstant;
import org.elanfox.intellicommunity.common.ienum.EquipmentEnum;
import org.elanfox.intellicommunity.common.ienum.base.CodeDescEnumHelper;
import org.elanfox.intellicommunity.common.utils.ExcelHelper;
import org.elanfox.intellicommunity.data.base.base.AbstractSearchableCrudService;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.elanfox.intellicommunity.msg.ienum.BaseStationType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基站service
 *
 * @author loutianxi
 * @date 2019-12-05
 */
@Service
public class BaseStationServiceImpl extends AbstractSearchableCrudService<BaseStationPO, Integer> implements BaseStationService {

    @Autowired
    private BaseStationRepository repository;
    @Autowired
    private LocatorService locatorService;

    private static final String strTrue = "是";

    protected BaseStationServiceImpl(BaseStationRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<BaseStationPO> specificationAndSort(BaseSearchDTO condition) {
        BaseStationCondition baseStationCondition = (BaseStationCondition) condition;
        Specification<BaseStationPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (baseStationCondition.getNo() != null) {
                predicates.add(cb.equal(root.get(BaseStationPO_.no), baseStationCondition.getNo()));
            }
            if (baseStationCondition.getStatus() != null) {
                predicates.add(cb.equal(root.get(BaseStationPO_.status), baseStationCondition.getStatus()));
            }
            if (baseStationCondition.getEnable() != null) {
                predicates.add(cb.equal(root.get(BaseStationPO_.enable), baseStationCondition.getEnable()));
            }
            if (baseStationCondition.getDismantleStatus() != null) {
                predicates.add(cb.equal(root.get(BaseStationPO_.dismantleStatus), baseStationCondition.getDismantleStatus()));
            }
            if (baseStationCondition.getOnlineStatus() != null) {
                predicates.add(cb.equal(root.get(BaseStationPO_.onlineStatus), baseStationCondition.getOnlineStatus()));
            }
            if (baseStationCondition.getVoltageStatus() != null) {
                EquipmentEnum.VoltageStatusEnum voltageStatus = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.VoltageStatusEnum.class, baseStationCondition.getVoltageStatus());
                predicates.add(cb.equal(root.get(BaseStationPO_.voltageStatus), voltageStatus));
            }
            if (baseStationCondition.getType() != -1) {
                EquipmentEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, baseStationCondition.getType());
                predicates.add(cb.equal(root.get(BaseStationPO_.type), type));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public BaseStationPO save(BaseSaveDTO saveDTO) {
        BaseStationSaveDTO baseStationSaveDTO = (BaseStationSaveDTO) saveDTO;
        BaseStationPO baseStationPO = findById(baseStationSaveDTO.getBaseStationId());

        //根据卡号获取卡PO
        BaseStationPO baseStationPO1 = repository.findByNo(baseStationSaveDTO.getNo());
        if (baseStationPO == null) {
            if (baseStationPO1 != null) {
                throw new IllegalStateException("基站编号已经存在");
            }
            baseStationPO = new BaseStationPO();
            baseStationPO.initStatus();
        } else {
            if (baseStationPO1 != null && baseStationPO1.getNo() != baseStationPO.getNo()) {
                throw new IllegalStateException("基站编号已经存在!");
            }
        }
        //保存基站
        baseStationPO.setIp(baseStationSaveDTO.getIp());
        //设备相关属性
        baseStationPO.setNo(baseStationSaveDTO.getNo());
        baseStationPO.setVersion(baseStationSaveDTO.getVersion());
        baseStationPO.setDeviceAddr(baseStationSaveDTO.getDeviceAddr());
        EquipmentEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, baseStationSaveDTO.getType());
        baseStationPO.setType(type);
        BaseStationType baseStationType = CodeDescEnumHelper.getEnumTypeByCode(BaseStationType.class, baseStationSaveDTO.getBaseStationType());
        baseStationPO.setStationType(baseStationType);
        baseStationPO.setDescribe(baseStationSaveDTO.getDescribe());
//        baseStationPO.setAlarmedImmediately(baseStationSaveDTO.getAlarmedImmediately() == 1);
//        baseStationPO.setAlarmTemplate(baseStationSaveDTO.getAlarmTemplate());
        //保存基站之前，保存基站绑定的定位器
        LocatorPO locatorPO = saveLocator(baseStationPO, baseStationPO.getLocator(), baseStationSaveDTO.getFloorNode());
        baseStationPO.setLocator(locatorPO);
        return repository.save(baseStationPO);
    }

    private LocatorPO saveLocator(BaseStationPO baseStationPO, LocatorPO locatorPO, Boolean floorNode) {
        if (locatorPO == null) {
            locatorPO = new LocatorPO();
            locatorPO.initStatus();
            locatorPO.setBindingBaseStation(true);
        }
        //设备相关属性
        locatorPO.setNo(baseStationPO.getNo());
        locatorPO.setVersion(baseStationPO.getVersion());
        switch (baseStationPO.getType()) {
            case TYPE_0:
                locatorPO.setType(EquipmentEnum.TypeEnum.TYPE_2);
                break;
            case TYPE_1:
                locatorPO.setType(EquipmentEnum.TypeEnum.TYPE_3);
                break;
            default:
                break;
        }
        LocatorInfo locatorInfo = new LocatorInfo();
        locatorInfo.setFloorNode(floorNode);
        locatorPO.setLocatorInfo(locatorInfo);
        locatorPO.setDescribe(baseStationPO.getDescribe());
        locatorPO.setShow(true);
        return locatorService.save(locatorPO);
    }

    @Override
    public boolean updateEnable(Integer baseStationId) {
        BaseStationPO baseStationPO = findById(baseStationId);
        if (baseStationPO != null) {
            repository.updateEnableById(baseStationId, !baseStationPO.isEnable());
            locatorService.updateEnable(baseStationPO.getNo());
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteByNo(Long no) {
        repository.deleteByNo(no);
        locatorService.deleteByNo(no);
        return true;
    }

    @Override
    public boolean updateDismantleStatus(Integer baseStationId) {
        BaseStationPO baseStationPO = findById(baseStationId);
        if (baseStationPO != null) {
            return repository.updateDismantleStatusById(baseStationId, !baseStationPO.isDismantleStatus()) > 0;
        }
        return false;
    }

    @Override
    public BaseStationPO findByDeviceAddr(long deviceAddr, BaseStationType stationType) {
        return repository.findByDeviceAddrAndStationType(deviceAddr, stationType);
    }

    @Override
    public void setLfScope(Integer stationId, int scope) {
        BaseStationPO stationPO = findById(stationId);
        stationPO.setLfScope(scope);

        save(stationPO);
    }

    @Override
    public void setRssiLimit(Integer stationId, boolean enabled, int limitVal) {
        BaseStationPO stationPO = findById(stationId);
        stationPO.setRssiEnabled(enabled);
        stationPO.setRssiLimitVal(limitVal);

        save(stationPO);
    }

    @Override
    public void setBuzzerStatus(Integer stationId, boolean enabled) {
        BaseStationPO stationPO = findById(stationId);
        stationPO.setBuzzerStatus(enabled);

        save(stationPO);
    }

    @Override
    public void setDeviceAddr(Integer stationId, long deviceAddr) {
        BaseStationPO stationPO = findById(stationId);
        stationPO.setDeviceAddr(deviceAddr);

        save(stationPO);
    }

    @Override
    public void setFilterTime(Integer stationId, int interval) {
        BaseStationPO stationPO = findById(stationId);
        stationPO.setFilterInterval(interval);
        save(stationPO);
    }

    @Override
    public void lead(MultipartFile updateFile) throws IOException {
        POIFSFileSystem fs = new POIFSFileSystem(updateFile.getInputStream());
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fs);
        List<List<ExcelHelper.CellDesc>> excelContent = ExcelHelper.readWorkbook(hssfWorkbook, "sheet1", 1, ExcelConstant.BASESTATION.length, 0);
        List<BaseStationPO> stationPOS = new ArrayList<>();
        if (excelContent != null) {
            for (List<ExcelHelper.CellDesc> r : excelContent) {
                if (r.get(0).getValue() == null) {
                    continue;
                }
                if (StringUtils.isEmpty(r.get(0).getValue().toString())) {
                    continue;
                }
                //根据excel创建基站对象
                long baseStationNo = Long.parseLong(r.get(0).getValue().toString().trim());
                BaseStationPO baseStationPO = repository.findByNo(baseStationNo);
                if (baseStationPO == null) {
                    baseStationPO = new BaseStationPO();
                    baseStationPO.initStatus();
                }
                baseStationPO.setNo(baseStationNo);
                baseStationPO.setVersion(r.get(1).getValue().toString().trim());
                baseStationPO.setType(CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, Integer.parseInt(r.get(2).getValue().toString().trim())));
                baseStationPO.setIp(r.get(3).getValue().toString().trim());
                baseStationPO.setStationType(CodeDescEnumHelper.getEnumTypeByCode(BaseStationType.class, Integer.parseInt(r.get(4).getValue().toString().trim())));
                baseStationPO.setDeviceAddr(Long.parseLong(r.get(5).getValue().toString().trim()));
                baseStationPO.setRawHexAddr(r.get(6).getValue().toString().trim());
                baseStationPO.setDescribe(r.get(7).getValue().toString().trim());
                //保存对应的定位器
                LocatorPO locatorPO = saveLocator(baseStationPO, baseStationPO.getLocator(), strTrue.equals(r.get(8).getValue().toString().trim()));
                baseStationPO.setLocator(locatorPO);
                stationPOS.add(baseStationPO);
            }
            save(stationPOS);
        }
    }

    @Override
    public Map<String,Long> count() {
        Map<String,Long> map=new HashMap<>();
        map.put("unonline",repository.countAllByOnlineStatusIsFalseAndEnableIsTrue());
        map.put("online",repository.countAllByOnlineStatusIsTrueAndEnableIsTrue());
        return map;
    }
}
